/*
  Provides an easy way to pick an object in a 3D scene.
  
  (c) copyright
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
 */

package picking;

import java.util.ArrayList;

import processing.core.*;

/**
 * A Picker object helps you to process picking.
 * 
 * @example Simple
 * @author nicolas.clavaud <antiplastik@gmail.com>
 *
 */
public class Picker {
	
	/**
	 * Processing applet
	 */
	protected PApplet parent;
	
	/**
	 * Main picking buffer
	 * Direct access to the buffer is allowed so you can draw shapes that
	 * you wouldn't like to draw on the main screen (like bounding boxes).
	 */
	public Buffer buffer;
	
	/**
	 * Class constructor
	 * 
	 * @param parent the currently running PApplet
	 */
	public Picker(PApplet parent) {
		this.parent = parent;
		buffer = (Buffer) parent.createGraphics(parent.width, parent.height, "picking.Buffer");
		buffer.callCheckSettings();
		if (parent.recorder == null) parent.recorder = buffer;
		buffer.background(0);
		parent.registerPre(this);
		parent.registerDraw(this);
	}
	
	/**
	 * This method is called before anything has been drawn
	 */
	public void pre() {
		buffer.beginDraw();
		if (parent.recorder == null) parent.recorder = buffer;
	}
	
	/**
	 * This method is called after everything has been drawn
	 */
	public void draw() {
		buffer.endDraw();
	}
	
	/**
	 * Begins recording object(s)
	 * 
	 * @param i an integer (between 0 and 16777214) identifying the object
	 */
	public void start(int i) {
		if (i < 0 || i > 16777214) {
			PApplet.println("[Picking error] start(): ID out of range");
			return;
		}
		if (parent.recorder == null) parent.recorder = buffer;
		buffer.setCurrentId(i);
	}
	
	/**
	 * Stops/pauses recording object(s)
	 */
	public void stop() {
		parent.recorder = null;
	}
	
	/**
	 * Resumes recording object(s)
	 */
	public void resume() {
		if (parent.recorder == null) parent.recorder = buffer;
	}
	
	/**
	 * Reads the ID of the object at point (x, y)
	 * <p>-1 means there is no object at this point
	 * 
	 * Modify to add more resistance for the aberrant value
	 * 
	 * @param x the x-coordinate
	 * @param y the y-coordinate
	 * @return  the object's ID at this coordinates
	 */
	public int get(int x, int y) {
		int value = buffer.getId(x, y);
		try {
			int valueBef = buffer.getId(x-2, y);
			int valueAft = buffer.getId(x+2, y);
			int valueUp = buffer.getId(x, y+2);
			int valueDown = buffer.getId(x, y-2);
			int valueUpLeft = buffer.getId(x-2, y+2);
			int valueDownLeft = buffer.getId(x-2, y-2);
			int valueUpRight = buffer.getId(x+2, y+2);
			int valueDownRight = buffer.getId(x+2, y-2);
			if(valueBef == value && valueAft == value && valueUp == value && valueDown == value){
				//value is ok
			}
			else{
				int[] tbl = {valueBef,valueAft,valueUp,valueDown,valueUpLeft,valueDownLeft,valueUpRight,valueDownRight};
				value = searchAndDisplay(tbl);
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
		return value;
	}
	
	// source : http://www.roseindia.net/tutorial/java/core/countOccurrenceOf%20Number.html
	/**
	 * This method give the most common value in an array of int
	 */
	public static int searchAndDisplay(int[] arr) {                
		ArrayList<Integer> list1 = new ArrayList<Integer>();                
		ArrayList<Integer> list2 = new ArrayList<Integer>();                
		for (int element : arr) {                        
			int index = list1.indexOf(element);                        
			if (index != -1) {                                
				int newCount = list2.get(index) + 1;                                
				list2.set(index, newCount);                        
			} else {                                
				list1.add(element);                                
				list2.add(1);                        
			}                
		}                              
		int maxCount = 0;                
		int index = -1;                
		for (int i = 0; i < list2.size(); i++) {                        
			if (maxCount < list2.get(i)) {                                
				maxCount = list2.get(i);                                
				index = i;                        
			}                
		}                
		return list1.get(index);        
	}
	
	/**
	 * Returns the buffer
	 * 
	 * @return Buffer
	 */
	public PGraphics getBuffer() {
		return buffer;
	}
	
}

